{
  // 泛型

  // 需求: 定义一个函数, 出入啥 返回啥
  // 我不管你传入的是什么类型, 只需要将你传入的类型 也同样交给返回值类型即可
  // T 就是类型变量, 专门接受类型 ===>>> 泛型
  function fn<T>(value: T): T {
    return value
  }

  //   fn(1)
  //   fn('ad')
  //   fn(true)

  fn<string>('ad')
  fn<number>(1)
  fn<boolean>(true)
}

{
  // 练习: 定义泛型函数
  // createArr(3, 1) [1,1,1]
  // createArr(3, 'a') ['a','a','a']

  function createArr<T>(length: number, item: T): Array<T> {
    let result: Array<T> = []
    for (let i = 0; i < length; i++) {
      result.push(item)
    }
    return result
  }

  function createArr1<T>(length: number, item: T): T[] {
    const arr = []
    for (let i = 0; i < length; i++) {
      arr.push(item)
    }
    return arr
  }

  const result = createArr1<number>(10, 10)
  console.log(result)

  const result1 = createArr1(2, 'a')
  console.log(result1)

  createArr1(3, true)
}

{
  // 需求: 定义一个泛型函数, 传入一个长度为2的数组, 返回交换以后的数组
  // swap([1, 2]) [2, 1]
  // swap([1, 'abc']) ['abc', 1]

  // 第一项的数据和返回的第二项数据类型是一样的, 另外的也是同样的情况
  function swap<T1, T2>(arr: [T1, T2]): [T2, T1] {
    return [arr[1], arr[0]]
  }

  const res = swap<boolean, string>([true, 'str'])
  res[0].indexOf

  console.log(swap<string, number>(['abc', 2]), '1-交换之后的数据')
  console.log(swap<boolean, number>([true, 2]), '2-交换之后的数据')

  //总结: 泛型的使用时机, 当你定义函数时, 函数参数的类型, 已经返回值的类型,互相之间关联
}
